home *** CD-ROM | disk | FTP | other *** search
/ Complete Linux / Complete Linux.iso / docs / apps / database / postgres / postgre4.z / postgre4 / src / rules / prs2 / prs2define.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-08-27  |  31.5 KB  |  1,132 lines

  1. /*-----------------------------------------------------------------------
  2.  * FILE:
  3.  *   prs2define.c
  4.  *
  5.  * IDENTIFICATION:
  6.  *   $Header: /private/postgres/src/rules/prs2/RCS/prs2define.c,v 1.26 1992/07/08 20:51:28 joey Exp $
  7.  *
  8.  * DESCRIPTION:
  9.  *   All the routines needed to define a (tuple level) PRS2 rule
  10.  */
  11.  
  12. #include "tmp/postgres.h"
  13. #include "nodes/primnodes.h"
  14. #include "nodes/primnodes.a.h"
  15. #include "nodes/pg_lisp.h"
  16. #include "utils/log.h"
  17. #include "utils/relcache.h"    /* RelationNameGetRelation() defined here...*/
  18. #include "rules/prs2.h"
  19. #include "access/skey.h"    /* 'ScanKeyEntryData' defined here... */
  20. #include "access/tqual.h"    /* 'NowTimeQual' defined here.. */
  21. #include "access/heapam.h"    /* heap AM calls defined here */
  22. #include "utils/lsyscache.h"    /* get_attnum()  defined here...*/
  23. #include "parser/parse.h"    /* RETRIEVE, APPEND etc defined here.. */
  24. #include "parser/parsetree.h"
  25. #include "catalog/catname.h"    /* names of various system relations */
  26. #include "utils/fmgr.h"    /* for F_CHAR16EQ, F_CHAR16IN etc. */
  27. #include "access/ftup.h"    /* for FormHeapTuple() */
  28. #include "utils/palloc.h"
  29.  
  30. #include "catalog/pg_proc.h"
  31. #include "catalog/pg_prs2rule.h"
  32. #include "catalog/pg_prs2plans.h"
  33.  
  34. extern LispValue planner();
  35. extern LispValue lispCopy();
  36.  
  37.  
  38. /*-----------------------------------------------------------------------
  39.  *
  40.  * prs2DefineTupleRule
  41.  *
  42.  * Define a tuple-level rule. This is the high-level interface.
  43.  *
  44.  *-----------------------------------------------------------------------
  45.  */
  46.  
  47. void
  48. prs2DefineTupleRule(parseTree, ruleText)
  49. LispValue parseTree;
  50. char *ruleText;
  51. {
  52.  
  53.     Prs2RuleData ruleData;
  54.     List hint;
  55.  
  56. #ifdef PRS2_DEBUG
  57.     printf("PRS2: ---prs2DefineTupleRule called, with argument =");
  58.     lispDisplay(parseTree);
  59.     printf("\n");
  60.     printf("PRS2:   ruletext = %s\n", ruleText);
  61. #endif PRS2_DEBUG
  62.     
  63.     /*
  64.      * find the rule "hint", i.e. see if the user explicitly
  65.      * stated what kind of lock he/she/it/ wnated to use.
  66.      */
  67.     hint = GetRuleHintFromParse(parseTree);
  68.     
  69.     /*
  70.      * extract some rule info form the parsetree...
  71.      */
  72.     ruleData = prs2FindRuleData(parseTree, ruleText);
  73.  
  74.     /*
  75.      * now put locks/stubs and update system catalogs...
  76.      */
  77.     prs2AddTheNewRule(ruleData, hint);
  78.  
  79. #ifdef PRS2_DEBUG
  80.     printf("PRS2: --- DEFINE PRS2 RULE: Done.\n");
  81. #endif PRS2_DEBUG
  82. }
  83.  
  84. /*-----------------------------------------------------------------------
  85.  * prs2RemoveTupleRule
  86.  *
  87.  * Remove a tuple-system rule given its name.
  88.  *
  89.  *-----------------------------------------------------------------------
  90.  */
  91. void
  92. prs2RemoveTupleRule(ruleName)
  93. Name ruleName;
  94. {
  95.     ObjectId ruleId;
  96.  
  97.     /*
  98.      * first find its oid & then remove it...
  99.      */
  100.     ruleId = get_ruleid(ruleName);
  101.     if (ruleId == InvalidObjectId) {
  102.     elog(WARN, "Rule '%s' does not exist!", ruleName);
  103.     }
  104.  
  105.     prs2DeleteTheOldRule(ruleId);
  106. }
  107.  
  108. /*-----------------------------------------------------------------------
  109.  * prs2FindRuleData
  110.  *
  111.  * create a 'Prs2RuleData' struct & fill it with all the information
  112.  * about this rule we will ever need to know...
  113.  *
  114.  *-----------------------------------------------------------------------
  115.  */
  116. Prs2RuleData
  117. prs2FindRuleData(parseTree, ruleText)
  118. List parseTree;
  119. char *ruleText;
  120. {
  121.     Prs2RuleData r;
  122.     List eventTarget;
  123.     Relation rel;
  124.     bool newUsed, currentUsed;
  125.  
  126.     /*
  127.      * create the structure where we hold all the rule
  128.      * information we need to know...
  129.      */
  130.     r = (Prs2RuleData) palloc(sizeof(Prs2RuleDataData));
  131.     if (r==NULL) {
  132.     elog(WARN, "prs2FindRuleInfo: Out of memory");
  133.     }
  134.     r->ruleName = (Name) palloc(sizeof(NameData));
  135.     if (r->ruleName == NULL) {
  136.     elog(WARN, "prs2FindRuleInfo: Out of memory");
  137.     }
  138.     r->eventRelationName = (Name) palloc(sizeof(NameData));
  139.     if (r->eventRelationName == NULL) {
  140.     elog(WARN, "prs2FindRuleInfo: Out of memory");
  141.     }
  142.     r->eventAttributeName = (Name) palloc(sizeof(NameData));
  143.     if (r->eventAttributeName == NULL) {
  144.     elog(WARN, "prs2FindRuleInfo: Out of memory");
  145.     }
  146.     
  147.     /*
  148.      * start filling it in...
  149.      * NOTE: we do not know yet the rule oid...
  150.      */
  151.     r->ruleId = InvalidObjectId;
  152.     r->parseTree = parseTree;
  153.     r->ruleText = ruleText;
  154.     strcpy(r->ruleName->data, CString(GetRuleNameFromParse(parseTree)));
  155.  
  156.     if  (CInteger(GetRuleInsteadFromParse(parseTree)) != 0)
  157.     r->isInstead = true;
  158.     else
  159.     r->isInstead = false;
  160.     r->eventType = prs2FindEventTypeFromParse(parseTree);
  161.  
  162.     /*
  163.      * 
  164.      * Find the OID of the relation to be locked, and the
  165.      * attribute number of the locked attribute. If no such 
  166.      * attribute has been specified, use 'InvalidAttributeNumber'
  167.      * instead.
  168.      *
  169.      * NOTE: 'eventTarget' is a list of one or two items.
  170.      * The first one is the name of the relation and the optional second
  171.      * one is the attribute name
  172.      *
  173.      * XXX: this should change in the future! It would be better
  174.      * that the parser will return a list with the relation OID
  175.      * and the attibute number instead of their names!
  176.      */
  177.     eventTarget = GetRuleEventTargetFromParse(parseTree);
  178.     strcpy(r->eventRelationName->data, CString(CAR(eventTarget)));
  179.     rel = RelationNameGetRelation(r->eventRelationName);
  180.     r->eventRelationOid = rel->rd_id;
  181.     if (null(CDR(eventTarget))) {
  182.     /*
  183.      * no attribute is specified
  184.      */
  185.     r->eventAttributeNumber = InvalidAttributeNumber;
  186.     r->eventAttributeName = NULL;
  187.     } else {
  188.     strcpy(r->eventAttributeName->data, CString(CADR(eventTarget)));
  189.     r->eventAttributeNumber = get_attnum(r->eventRelationOid,
  190.                         r->eventAttributeName);
  191.     if (r->eventAttributeNumber == InvalidAttributeNumber) {
  192.         elog(WARN,"Illegal attribute in event target list");
  193.     }
  194.     /*
  195.      * XXX currently we only allow tuple-level rules to
  196.      * be defined in attributes of basic types (i.e. not of type
  197.      * relation etc....)
  198.      */
  199.     if (!prs2AttributeIsOfBasicType(r->eventRelationOid,
  200.                     r->eventAttributeNumber)) {
  201.         elog(WARN,
  202.         "Can not define tuple rules in non-base type attributes");
  203.     }
  204.     /*
  205.      * "on delete" and "on append" rules must not have an attribute
  206.      * specified in the event clause.
  207.      */
  208.     if (r->eventType == EventTypeDelete)
  209.         elog(WARN,
  210.         "On Delete rules must not have an attribute in their event clause");
  211.     if (r->eventType == EventTypeAppend)
  212.         elog(WARN,
  213.         "On Append rules must not have an attribute in their event clause");
  214.     }
  215.  
  216.     /*
  217.      * check if we use CURRENT on a 'on append' rule, or NEW
  218.      * on a 'on retrieve' or 'on delete' rule.
  219.      * If yes, then complain...
  220.      */
  221.     r->ruleQual = GetRuleQualFromParse(parseTree);
  222.     r->ruleAction = GetRuleActionFromParse(parseTree);
  223.     IsPlanUsingNewOrCurrent(r->ruleQual, ¤tUsed, &newUsed);
  224.     if (currentUsed && r->eventType == EventTypeAppend) {
  225.     elog(WARN,
  226.         "An `on append' rule, can not reference the 'current' tuple");
  227.     }
  228.     if (newUsed && r->eventType == EventTypeRetrieve) {
  229.     elog(WARN,
  230.         "An `on retrieve' rule, can not reference the 'new' tuple");
  231.     }
  232.     if (newUsed && r->eventType == EventTypeDelete) {
  233.     elog(WARN,
  234.         "An `on delete' rule, can not reference the 'new' tuple");
  235.     }
  236.     IsPlanUsingNewOrCurrent(r->ruleAction, ¤tUsed, &newUsed);
  237.     if (currentUsed && r->eventType == EventTypeAppend) {
  238.     elog(WARN,
  239.         "An `on append' rule, can not reference the 'current' tuple");
  240.     }
  241.     if (newUsed && r->eventType == EventTypeRetrieve) {
  242.     elog(WARN,
  243.         "An `on retrieve' rule, can not reference the 'new' tuple");
  244.     }
  245.     if (newUsed && r->eventType == EventTypeDelete) {
  246.     elog(WARN,
  247.         "An `on delete' rule, can not reference the 'new' tuple");
  248.     }
  249.  
  250.     /*
  251.      * The parsetree generated by the parser has a NEW and/or CURRENT
  252.      * entries in the range table. In order to find the rule qualification
  253.      * and the action plans to be executed at rule activation time,
  254.      * we have to change all the corresponding "Var" nodes to the
  255.      * appropriate "Param" nodes.
  256.      * Note however, that we must also keep the original rule qualification 
  257.      * (i.e. the one with the "Var" nodes) because it is needed to
  258.      * calculate the appropriate stub records etc.
  259.      * nodes to the equivalent
  260.      */
  261.     r->paramParseTree = lispCopy(parseTree);
  262.     SubstituteParamForNewOrCurrent(r->paramParseTree, r->eventRelationOid);
  263.     r->paramRuleQual = GetRuleQualFromParse(r->paramParseTree);
  264.     r->paramRuleAction = GetRuleActionFromParse(r->paramParseTree);
  265.  
  266.     /*
  267.      * Now, find the type of action. (i.e. ActionTypeRetrieve, 
  268.      * ActionTypeReplaceCurrent or ActionTypeOther).
  269.      * In the first 2 cases,  `updatedAttributeNumber' is the number
  270.      * of attribute beeing updated.
  271.      */
  272.     r->actionType = prs2FindActionTypeFromParse(r->parseTree,
  273.             r->eventAttributeNumber,
  274.             &(r->updatedAttributeNumber),
  275.             r->eventType);
  276.     /*
  277.      * Hm... for the time being we do NOT allow 
  278.      *     ON RETRIEVE ... DO RETRIEVE ....
  279.      * rules without an INSTEAD
  280.      * unless this is a "view" rule (i.e. something
  281.      * like "on retrieve to TOYEMP do retrieve...")
  282.      * In this case the event target object must be a
  283.      * relation and not a "relation.attribute"
  284.      */
  285.     if (!(r->isInstead) && r->actionType == ActionTypeRetrieveValue &&
  286.     r->eventAttributeNumber != InvalidAttributeNumber ) {
  287.     elog(WARN,
  288.     "`on retrieve ... do retrieve' tuple rules must have an `instead'");
  289.     }
  290.  
  291.  
  292. #ifdef PRS2_DEBUG
  293.     {
  294.     printf("PRS2: ---DEFINE TUPLE RULE:\n");
  295.     printf("PRS2:    RuleName = %s\n", r->ruleName->data);
  296.     printf("PRS2:    event type = %d ", r->eventType);
  297.     switch (r->eventType) {
  298.     case EventTypeRetrieve:
  299.         printf("(retrieve)\n");
  300.         break;
  301.     case EventTypeReplace:
  302.         printf("(replace)\n");
  303.         break;
  304.     case EventTypeAppend:
  305.         printf("(append)\n");
  306.         break;
  307.     case EventTypeDelete:
  308.         printf("(delete)\n");
  309.         break;
  310.     default:
  311.         printf("(*** UNKNOWN ***)\n");
  312.     }
  313.     printf("PRS2:    event target:");
  314.     lispDisplay(eventTarget);
  315.     printf("\n");
  316.     printf("PRS2:    event target relation OID = %ld\n", r->eventRelationOid);
  317.     printf("PRS2:    event target attr no = %d\n", r->eventAttributeNumber);
  318.     printf("PRS2:    Instead flag = %d\n", r->isInstead);
  319.     printf("PRS2:    ruleAction:");
  320.     lispDisplay(r->paramRuleAction);
  321.     printf("\n");
  322.     }
  323. #endif PRS2_DEBUG
  324.     
  325.     return(r);
  326. }
  327.  
  328.  
  329. /*-----------------------------------------------------------------------
  330.  *
  331.  * prs2InsertRuleInfoInCatalog
  332.  *
  333.  * Insert information about a rule in the rules system catalog.
  334.  * As the rule names are unique, we have first to make sure
  335.  * that no other rule with the same names exists.
  336.  *
  337.  *-----------------------------------------------------------------------
  338.  */
  339. ObjectId
  340. prs2InsertRuleInfoInCatalog(r)
  341. Prs2RuleData r;
  342. {
  343.     register        i;
  344.     Relation        prs2RuleRelation;
  345.     HeapTuple        heapTuple;
  346.     char        *values[Prs2RuleRelationNumberOfAttributes];
  347.     char        nulls[Prs2RuleRelationNumberOfAttributes];
  348.     ObjectId        objectId;
  349.     HeapScanDesc    heapScan;
  350.     ScanKeyEntryData    ruleNameKey[1];
  351.  
  352.  
  353.     
  354.     /*
  355.      * Open the system catalog relation
  356.      * where we keep the rule info (pg_prs2rule)
  357.      */
  358.     prs2RuleRelation = RelationNameOpenHeapRelation(Prs2RuleRelationName);
  359.     if (!RelationIsValid(prs2RuleRelation)) {
  360.     elog(WARN, "prs2InsertRuleInfoCatalog: could not open relation %s",
  361.          Prs2RuleRelationName);
  362.     }
  363.  
  364.     /*
  365.      * First make sure that no other rule with the same name exists!
  366.      */
  367.     ScanKeyEntryInitialize(&ruleNameKey[0], 0, Prs2RuleNameAttributeNumber,
  368.                            F_CHAR16EQ, NameGetDatum(r->ruleName));
  369.  
  370.     heapScan = RelationBeginHeapScan(prs2RuleRelation, false, NowTimeQual,
  371.                      1, (ScanKey) ruleNameKey);
  372.     heapTuple = HeapScanGetNextTuple(heapScan, false, (Buffer *) NULL);
  373.     if (HeapTupleIsValid(heapTuple)) {
  374.     HeapScanEnd(heapScan);
  375.     RelationCloseHeapRelation(prs2RuleRelation);
  376.     elog(WARN, "Sorry, rule %s is already defined",
  377.          r->ruleName);
  378.     }
  379.     HeapScanEnd(heapScan);
  380.  
  381.     /*
  382.      * Now create a tuple with the new rule info
  383.      */
  384.     for (i = 0; i < Prs2RuleRelationNumberOfAttributes; ++i) {
  385.     values[i] = NULL;
  386.     nulls[i] = 'n';
  387.     }
  388.  
  389.     values[Prs2RuleNameAttributeNumber-1] =
  390.                 fmgr(F_CHAR16IN,(char *)(r->ruleName));
  391.     nulls[Prs2RuleNameAttributeNumber-1] = ' ';
  392.  
  393.     values[Prs2RuleEventTypeAttributeNumber-1] = (char *) r->eventType;
  394.     nulls[Prs2RuleEventTypeAttributeNumber-1] = ' ';
  395.  
  396.     values[Prs2RuleEventTargetRelationAttributeNumber-1] =
  397.             (char *) r->eventRelationOid;
  398.     nulls[Prs2RuleEventTargetRelationAttributeNumber-1] = ' ';
  399.  
  400.     values[Prs2RuleEventTargetAttributeAttributeNumber-1] = 
  401.             (char *) r->eventAttributeNumber;
  402.     nulls[Prs2RuleEventTargetAttributeAttributeNumber-1] = ' ';
  403.  
  404.     values[Prs2RuleTextAttributeNumber-1] = 
  405.             fmgr(F_TEXTIN, r->ruleText);
  406.     nulls[Prs2RuleTextAttributeNumber-1] = ' ';
  407.  
  408.     heapTuple = FormHeapTuple(Prs2RuleRelationNumberOfAttributes,
  409.                   &prs2RuleRelation->rd_att, values, nulls);
  410.  
  411.     /*
  412.      * Now insert the tuple in the system catalog
  413.      * and return its OID (which form now on is the rule's id.
  414.      */
  415.     (void) RelationInsertHeapTuple(prs2RuleRelation, heapTuple,
  416.                    (double *) NULL);
  417.     objectId = heapTuple->t_oid;
  418.     RelationCloseHeapRelation(prs2RuleRelation);
  419.     return(objectId);
  420. }
  421.  
  422. /*-----------------------------------------------------------------------
  423.  * prs2DeleteRuleInfoFromCatalog
  424.  *
  425.  * remove all rule info stored in 'pg_prs2rule' about the given
  426.  * rule.
  427.  *
  428.  *-----------------------------------------------------------------------
  429.  */
  430. void
  431. prs2DeleteRuleInfoFromCatalog(ruleId)
  432. ObjectId ruleId;
  433. {
  434.     Relation prs2RuleRelation;
  435.     HeapScanDesc scanDesc;
  436.     ScanKeyData scanKey;
  437.     HeapTuple tuple;
  438.     Buffer buffer;
  439.  
  440.     /*
  441.      * Open the pg_rule relation. 
  442.      */
  443.     prs2RuleRelation = RelationNameOpenHeapRelation(Prs2RuleRelationName);
  444.  
  445.      /*
  446.       * Scan the RuleRelation ('pg_prs2rule') until we find a tuple
  447.       */
  448.     ScanKeyEntryInitialize(&scanKey.data[0], 0, ObjectIdAttributeNumber,
  449.                            ObjectIdEqualRegProcedure,
  450.                            ObjectIdGetDatum(ruleId));
  451.  
  452.     scanDesc = RelationBeginHeapScan(prs2RuleRelation,
  453.                     false, NowTimeQual, 1, &scanKey);
  454.  
  455.     tuple = HeapScanGetNextTuple(scanDesc, false, &buffer);
  456.  
  457.     /*
  458.      * complain if no such rule existed
  459.      */
  460.     if (!HeapTupleIsValid(tuple)) {
  461.     RelationCloseHeapRelation(prs2RuleRelation);
  462.     elog(WARN, "No rule with id = '%d' was found.\n", ruleId);
  463.     }
  464.  
  465.     /*
  466.      * Now delete the tuple...
  467.      */
  468.     RelationDeleteHeapTuple(prs2RuleRelation, &(tuple->t_ctid));
  469.     RelationCloseHeapRelation(prs2RuleRelation);
  470.     HeapScanEnd(scanDesc);
  471. }
  472.  
  473. /*-----------------------------------------------------------------------
  474.  *
  475.  * prs2InsertRulePlanInCatalog
  476.  *
  477.  *    Insert a rule plan into the appropriate system catalogs.
  478.  *    Arguments:
  479.  *    ruleId        the OID of the rule (as returned by routine
  480.  *            'prs2InsertRuleInfoInCatalog').
  481.  *    planNumber    the corresponding planNumber.
  482.  *    rulePlan    the rule plan itself!
  483.  *
  484.  *-----------------------------------------------------------------------
  485.  */
  486. void
  487. prs2InsertRulePlanInCatalog(ruleId, planNumber, rulePlan)
  488. ObjectId ruleId;
  489. Prs2PlanNumber planNumber;
  490. List rulePlan;
  491. {
  492.     register        i;
  493.     char        *rulePlanString;
  494.     Relation        prs2PlansRelation;
  495.     HeapTuple        heapTuple;
  496.     char        *values[Prs2PlansRelationNumberOfAttributes];
  497.     char        nulls[Prs2PlansRelationNumberOfAttributes];
  498.  
  499.     
  500.     /*
  501.      * Open the system catalog relation
  502.      */
  503.     prs2PlansRelation=RelationNameOpenHeapRelation(Prs2PlansRelationName);
  504.     if (!RelationIsValid(prs2PlansRelation)) {
  505.     elog(WARN, "prs2InsertRulePlanInCatalog: could not open relation %s",
  506.          Prs2PlansRelationName);
  507.     }
  508.  
  509.     /*
  510.      * Create the appropriate tuple.
  511.      * NOTE: 'rulePlan' is of type LispValue, so we have first
  512.      * to transform it to a string using 'PlanToString()'
  513.      */
  514.     rulePlanString = PlanToString(rulePlan);
  515.  
  516.     for (i = 0; i < Prs2PlansRelationNumberOfAttributes; ++i) {
  517.     nulls[i] = ' ';
  518.     }
  519.  
  520.     values[Prs2PlansRuleIdAttributeNumber-1] = (char *) ruleId;
  521.     values[Prs2PlansPlanNumberAttributeNumber-1] = (char *) planNumber;
  522.     values[Prs2PlansCodeAttributeNumber-1] = fmgr(F_TEXTIN,rulePlanString);
  523.     
  524.     heapTuple = FormHeapTuple(Prs2PlansRelationNumberOfAttributes,
  525.                   &prs2PlansRelation->rd_att, values, nulls);
  526.  
  527.     /*
  528.      * Now insert the tuple to the system catalog.
  529.      */
  530.     (void) RelationInsertHeapTuple(prs2PlansRelation,
  531.                 heapTuple, (double *) NULL);
  532.     RelationCloseHeapRelation(prs2PlansRelation);
  533.     pfree(rulePlanString);
  534.  
  535. }
  536.  
  537. /*--------------------------------------------------------------------------
  538.  * prs2DeleteRulePlanFromCatalog
  539.  *
  540.  * Delete all rule plans for the given rule from the "pg_prs2plans"
  541.  * system catalog.
  542.  *--------------------------------------------------------------------------
  543.  */
  544. void
  545. prs2DeleteRulePlanFromCatalog(ruleId)
  546. ObjectId ruleId;
  547. {
  548.     Relation prs2PlansRelation;
  549.     HeapScanDesc scanDesc;
  550.     ScanKeyData scanKey;
  551.     HeapTuple tuple;
  552.     Buffer buffer;
  553.  
  554.     /*
  555.      * Delete all tuples of the Prs2Plans relation (pg_prs2plans)
  556.      * corresponding to this rule...
  557.      */
  558.     prs2PlansRelation = RelationNameOpenHeapRelation(Prs2PlansRelationName);
  559.  
  560.     ScanKeyEntryInitialize(&scanKey.data[0], 0, Prs2PlansRuleIdAttributeNumber,
  561.                            ObjectIdEqualRegProcedure,
  562.                            ObjectIdGetDatum(ruleId));
  563.  
  564.     scanDesc = RelationBeginHeapScan(prs2PlansRelation,
  565.                     false, NowTimeQual, 1, &scanKey);
  566.  
  567.  
  568.     while((tuple=HeapScanGetNextTuple(scanDesc,false,(Buffer *)NULL)) !=NULL) {
  569.     /*
  570.      * delete the prs2PlansRelation tuple...
  571.      */
  572.     RelationDeleteHeapTuple(prs2PlansRelation, &(tuple->t_ctid));
  573.     }
  574.     
  575.     RelationCloseHeapRelation(prs2PlansRelation);
  576.     HeapScanEnd(scanDesc);
  577.  
  578. }
  579.  
  580. /*----------------------------------------------------------------------
  581.  *
  582.  * prs2GenerateActionPlans
  583.  *
  584.  * generate the plan+parse trees for the action part of the rule
  585.  *
  586.  *----------------------------------------------------------------------
  587.  */
  588. LispValue
  589. prs2GenerateActionPlans(r)
  590. Prs2RuleData r;
  591. {
  592.     LispValue result;
  593.     LispValue action;
  594.     LispValue oneParse;
  595.     LispValue onePlan;
  596.     LispValue oneEntry;
  597.     LispValue qualQuery;
  598.     LispValue ruleInfo;
  599.     LispValue rangeTable;
  600.     AttributeNumber currentAttributeNo;
  601.  
  602.  
  603.     rangeTable = GetRuleRangeTableFromParse(r->parseTree);
  604.  
  605.     /*
  606.      * the first entry in the result is some rule info
  607.      * This consists of the following fields:
  608.      * a) "instead" or "not-instead"
  609.      * b) the attribute number of the attribute specified
  610.      *    in the ON EVENT TO REL.attribute clause
  611.      *    (or InvalidAttributeNumber)
  612.      * c) either InvalidAttributeNumber, or in the case of a rule
  613.      *    of the form:
  614.      *       ON REPLACE TO REL.x WHERE ....
  615.      *       DO REPLACE CURRENT.attribute
  616.      *    the 'attribute' that is replced by the rule.
  617.      */
  618.     if (r->isInstead) {
  619.     ruleInfo = lispCons(lispString("instead"), LispNil);
  620.     } else {
  621.     ruleInfo = lispCons(lispString("not-instead"), LispNil);
  622.     }
  623.  
  624.     ruleInfo = nappend1(ruleInfo, lispInteger(r->eventAttributeNumber));
  625.     ruleInfo = nappend1(ruleInfo, lispInteger(r->updatedAttributeNumber));
  626.  
  627.     result = lispCons(ruleInfo, LispNil);
  628.  
  629.  
  630.     /*
  631.      * now append the qual entry (parse tree + plan)
  632.      */
  633.     if (null(r->ruleQual)) {
  634.     oneEntry = LispNil;
  635.     } else {
  636.     /*
  637.      * the 'ruleQual' is just a qualification.
  638.      * Transform it into a query of the form:
  639.      * "retrieve (foo=1) where QUAL".
  640.      * The rule manager will run this query and if there is 
  641.      * a tuple returned, then we know that the qual is true,
  642.      * otherwise we know it is false
  643.      */
  644.     LispValue MakeRoot();
  645.     LispValue root, targetList;
  646.     Resdom resdom;
  647.     Const constant;
  648.     Name name;
  649.     Datum value;
  650.  
  651.     /*
  652.      * construct the target list
  653.      */
  654.     name = (Name) palloc(sizeof(NameData));
  655.     if (name == NULL) {
  656.         elog(WARN, "prs2GenerateActionPlans: Out of memory");
  657.     }
  658.     strcpy(name->data,"foo");
  659.     resdom = MakeResdom((AttributeNumber)1,
  660.                 (ObjectId) 23,
  661.                 false,
  662.                 (Size) 4,
  663.                 name,
  664.                 (Index) 0,
  665.                 (OperatorTupleForm) 0,
  666.                 0);
  667.     value = Int32GetDatum(1);
  668.     constant = MakeConst((ObjectId) 23,    /* type */
  669.                 (Size) 4,        /* size */
  670.                 value,        /* value */
  671.                 false,        /* isnull */
  672.                 true);        /* byval */
  673.     targetList = lispCons(
  674.             lispCons((LispValue)resdom,
  675.                  lispCons((LispValue)constant, LispNil)),
  676.             LispNil);
  677.     /*
  678.      * now the root
  679.      * XXX NumLevels == 1 ??? IS THIS CORRECT ????
  680.      */
  681.     root = MakeRoot(
  682.             1,            /* num levels */
  683.             lispAtom("retrieve"),    /* command */
  684.             LispNil,        /* result relation */
  685.             rangeTable,        /* range table */
  686.             lispInteger(0),        /* priority */
  687.             LispNil,        /* rule info */
  688.             LispNil,        /* unique flag */
  689.             LispNil,        /* sort_clause */
  690.             targetList);        /* targetList */
  691.     /*
  692.      * Finally, construct the parse tree...
  693.      */
  694.     qualQuery = lispCons(root,
  695.             lispCons(targetList,
  696.                 lispCons(r->paramRuleQual, LispNil)));
  697.     onePlan = planner(qualQuery);
  698.     oneEntry = lispCons(onePlan, LispNil);
  699.     oneEntry = lispCons(qualQuery, oneEntry);
  700.     }
  701.     result = nappend1(result, oneEntry);
  702.  
  703.     /*
  704.      * Now for each action append the corresponding entry
  705.      * (parse tree + plan)
  706.      */
  707.     foreach (action, r->paramRuleAction) {
  708.     oneParse = CAR(action);
  709.     /*
  710.      * XXX: THIS IS A HACK !!!
  711.      *      (but it works, so what the hell....) 
  712.      *
  713.      * if this is a REPLACE CURRENT (X = ...)
  714.      * change it to a RETRIEVE (X = ...)
  715.      */
  716.     changeReplaceToRetrieve(oneParse);
  717.     /*
  718.      * call the planner to create a plan for this parse tree
  719.      */
  720.     onePlan = planner(oneParse);
  721.     oneEntry = lispCons(onePlan, LispNil);
  722.     oneEntry = lispCons(oneParse, oneEntry);
  723.     result = nappend1(result, oneEntry);
  724.     }
  725.  
  726.     /*
  727.      * finally insert itn the beginning of the list the
  728.      * string Prs2RulePlanType_ACTION to show that this is
  729.      * an action plan (as opposed to an import/export plan).
  730.      */
  731.     result = lispCons(lispString(Prs2RulePlanType_ACTION), result);
  732.  
  733.     return(result);
  734. }
  735.  
  736. /*------------------------------------------------------------------
  737.  *
  738.  * prs2FindEventTypeFromParse
  739.  *
  740.  * Given a rule's parse tree find its event type.
  741.  *------------------------------------------------------------------
  742.  */
  743. EventType
  744. prs2FindEventTypeFromParse(parseTree)
  745. LispValue parseTree;
  746. {
  747.  
  748.     int eventTypeInt;
  749.     EventType eventType;
  750.  
  751.     eventTypeInt = CInteger(GetRuleEventTypeFromParse(parseTree));
  752.  
  753.     /*
  754.      * Note that the event type as stored in the parse tree is one of
  755.      * RETRIEVE, REPLACE, APPEND or DELETE. All these symbols are
  756.      * defined in "parse.h". So, we have to change them
  757.      * into the appropriate "EventType" type.
  758.      */
  759.     switch (eventTypeInt) {
  760.     case RETRIEVE:
  761.         eventType = EventTypeRetrieve;
  762.         break;
  763.     case REPLACE:
  764.         eventType = EventTypeReplace;
  765.         break;
  766.     case APPEND:
  767.         eventType = EventTypeAppend;
  768.         break;
  769.     case DELETE:
  770.         eventType = EventTypeDelete;
  771.         break;
  772.     default:
  773.         eventType = EventTypeInvalid;
  774.         elog(WARN, "prs2DefineTupleRule: Illegal event type (int) %d",
  775.         eventTypeInt);
  776.     } /* switch*/
  777.  
  778.     return(eventType);
  779. }
  780.  
  781. /*------------------------------------------------------------------
  782.  *
  783.  * prs2FindActionTypeFromParse
  784.  *
  785.  * find the ActionType of a rule.
  786.  *
  787.  * if the action is in the form 'REPLACE CURRENT(x = ....)'
  788.  * then (*updatedAttributeNumber) is the attribute number of the
  789.  * updated field, otherwise it is InvalidAttributeNumber.
  790.  *------------------------------------------------------------------
  791.  */
  792. ActionType
  793. prs2FindActionTypeFromParse(parseTree,
  794.                 eventTargetAttributeNumber,
  795.                 updatedAttributeNumberP,
  796.                 eventType)
  797. LispValue parseTree;
  798. AttributeNumber eventTargetAttributeNumber;
  799. AttributeNumberPtr updatedAttributeNumberP;
  800. EventType eventType;
  801. {
  802.     
  803.     LispValue ruleActions;
  804.     LispValue t, oneRuleAction;
  805.     LispValue root;
  806.     int commandType;
  807.     LispValue resultRelation;
  808.     LispValue rangeTable;
  809.     ActionType actionType;
  810.     Name relationName;
  811.     NameData nameData;
  812.     LispValue targetList;
  813.     int resultRelationNo;
  814.     LispValue resultRelationEntry;
  815.  
  816.     *updatedAttributeNumberP = InvalidAttributeNumber;
  817.  
  818.     ruleActions = GetRuleActionFromParse(parseTree);
  819.  
  820.     if (null(ruleActions)) {
  821.     if (eventType != EventTypeRetrieve) {
  822.         /*
  823.          * then this is probably an `instead' rule with no action
  824.          * specified, e.g. "ON delete to DEPT WHERE ... DO INSTEAD"
  825.          */
  826.         return(ActionTypeOther);
  827.     } else {
  828.         /*
  829.          * However, if we have something like:
  830.          * ON RETRIEVE THEN DO INSTEAD NOTHING
  831.          * we assume that this means do NOT retrieve a value,
  832.          * i.e. return a null attribute.
  833.          */
  834.         *updatedAttributeNumberP = eventTargetAttributeNumber;
  835.         return(ActionTypeRetrieveValue);
  836.     }
  837.     }
  838.  
  839.     foreach(t, ruleActions) {
  840.     oneRuleAction = CAR(t);
  841.     /*
  842.      * find the type of query (retrieve, delete etc...)
  843.      */
  844.     root = parse_root(oneRuleAction);
  845.     commandType = root_command_type(root);
  846.     resultRelation = root_result_relation(root);
  847.     rangeTable = root_rangetable(root);
  848.     if (!null(resultRelation)) {
  849.         if (commandType == RETRIEVE) {
  850.         /*
  851.          * This is a retrieve into, the result reln info
  852.          * is a list of junk.
  853.          */
  854.         strncpy(&(nameData.data[0]),
  855.             CString(CADR(resultRelation)), sizeof(NameData));
  856.         } else {
  857.         resultRelationNo = CInteger(resultRelation);
  858.         resultRelationEntry = nth(resultRelationNo-1, rangeTable);
  859.         strcpy(&(nameData.data[0]),
  860.         CString(rt_relname(resultRelationEntry)));
  861.         }
  862.         relationName = &nameData;
  863.     } else {
  864.         relationName = InvalidName;
  865.     }
  866.     if (commandType == RETRIEVE && null(resultRelation)) {
  867.         /*
  868.          * this is a "retrieve" (NOT a "retrieve into...")
  869.          * action.
  870.          * It can be either something like:
  871.          *    ON retrieve to EMP.salary 
  872.          *    WHERE ....
  873.          *    DO retrieve (salary = ....) where .....
  874.          *
  875.          * In which case only one 'retrieve' command is allowed
  876.          * in the action part of the rule, 
  877.          * or it can be a view type rule:
  878.          *    ON retrieve to TOYEMP
  879.          *    DO retrieve (EMP.all) where EMP.dept = "toy"
  880.          */
  881.         actionType = ActionTypeRetrieveValue;
  882.         break;     /* exit 'foreach' loop */
  883.  
  884.     } else if (commandType == REPLACE &&
  885.             /*
  886.              * Dangerous cast - it just happens that NameIsEqual()
  887.              * currently calls strncmp()
  888.              */
  889.             NameIsEqual((Name)"*CURRENT*", relationName)) {
  890.         /*
  891.          * this is a replace CURRENT(...)
  892.          */
  893.         actionType = ActionTypeReplaceCurrent;
  894.         /*
  895.          * find the updated attribute number...
  896.          */
  897.         targetList = parse_targetlist(oneRuleAction);
  898.         if (ExecTargetListLength(targetList) != 1) {
  899.         elog(WARN,
  900.         " a 'replace CURRENT(...)' must replace ONLY 1 attribute");
  901.         }
  902.         *updatedAttributeNumberP = 
  903.             get_resno((Resdom)tl_resdom(CAR(targetList)));
  904.         break;     /* exit 'foreach' loop */
  905.     } else if (commandType == REPLACE &&
  906.             NameIsEqual((Name)"*NEW*", relationName)) {
  907.         /*
  908.          * this is a replace NEW(...)
  909.          */
  910.         actionType = ActionTypeReplaceNew;
  911.         /*
  912.          * find the updated attribute number...
  913.          */
  914.         targetList = parse_targetlist(oneRuleAction);
  915.         if (ExecTargetListLength(targetList) != 1) {
  916.         elog(WARN,
  917.         " a 'replace NEW(...)' must replace ONLY 1 attribute");
  918.         }
  919.         *updatedAttributeNumberP =
  920.             get_resno((Resdom)tl_resdom(CAR(targetList)));
  921.         break;     /* exit 'foreach' loop */
  922.     } else {
  923.         actionType = ActionTypeOther;
  924.     }
  925.     } /* foreach */
  926.  
  927.     if (actionType == ActionTypeRetrieveValue) {
  928.     /*
  929.      * then this must be the ONLY statement in the rule actions!
  930.      */
  931.     if (length(ruleActions) != 1) {
  932.         elog(WARN,
  933.         "a 'retrieve (..)' must be the only action of a PRS2 rule!");
  934.     }
  935.     *updatedAttributeNumberP = eventTargetAttributeNumber;
  936.     }
  937.     
  938.     if (actionType == ActionTypeReplaceCurrent) {
  939.     /*
  940.      * then this must be the ONLY statement in the rule actions!
  941.      */
  942.     if (length(ruleActions) != 1) {
  943.         elog(WARN,
  944.         "a 'replace CURRENT(..)' must be the only action of a PRS2 rule!");
  945.     }
  946.     }
  947.  
  948.     if (actionType == ActionTypeReplaceNew) {
  949.     /*
  950.      * then this must be the ONLY statement in the rule actions!
  951.      */
  952.     if (length(ruleActions) != 1) {
  953.         elog(WARN,
  954.         "a 'replace NEW(..)' must be the only action of a PRS2 rule!");
  955.     }
  956.     }
  957.  
  958.     return(actionType);
  959. }
  960.  
  961. /*----------------------------------------------------------------
  962.  *
  963.  * changeReplaceToRetrieve
  964.  *
  965.  * Ghange the parse tree of a 'REPLACE CURRENT(X = ...)'
  966.  * or 'REPLACE NEW(X = ...)' command to a
  967.  * 'RETRIEVE (X = ...)'
  968.  *----------------------------------------------------------------
  969.  */
  970. void
  971. changeReplaceToRetrieve(parseTree)
  972. LispValue parseTree;
  973. {
  974.  
  975.     LispValue root;
  976.     LispValue targetList;
  977.     int commandType;
  978.     LispValue resultRelation;
  979.     LispValue rangeTable;
  980.     Name relationName;
  981.     NameData nameData;
  982.     int resultRelationNo;
  983.     LispValue resultRelationEntry;
  984.  
  985.  
  986.     root = parse_root(parseTree);
  987.     commandType = root_command_type(root);
  988.     resultRelation = root_result_relation(root);
  989.     rangeTable = root_rangetable(root);
  990.     if (!null(resultRelation)) {
  991.     if (commandType == RETRIEVE) {
  992.         /*
  993.          * This is a retrieve into, the result reln info
  994.          * is a list of junk.
  995.          */
  996.         strncpy(&(nameData.data[0]),
  997.             CString(CADR(resultRelation)), sizeof(NameData));
  998.     } else {
  999.         resultRelationNo = CInteger(resultRelation);
  1000.         resultRelationEntry = nth(resultRelationNo-1, rangeTable);
  1001.         strcpy(&(nameData.data[0]),
  1002.         CString(rt_relname(resultRelationEntry)));
  1003.     }
  1004.         relationName = &nameData;
  1005.     } else {
  1006.     relationName = InvalidName;
  1007.     }
  1008.  
  1009.     /*
  1010.      * Is this a REPLACE CURRENT command?
  1011.      */
  1012.     if (commandType!=REPLACE ||
  1013.        (!NameIsEqual((Name)"*CURRENT*", relationName) &&
  1014.        !NameIsEqual((Name)"*NEW*", relationName))) {
  1015.     /*
  1016.      * NO, this is not a REPLACE CURRENT or a REPLACE NEW command
  1017.      */
  1018.     return;
  1019.     }
  1020.  
  1021.     /*
  1022.      * Yes it is!
  1023.      *
  1024.      * Now *DESTRUCTIVELY* change the parse tree...
  1025.      * 
  1026.      * Change the command from 'replace' to 'retrieve'
  1027.      * and the result relation to 'nil'
  1028.      */
  1029.     root = parse_root(parseTree);
  1030.     root_command_type_atom(root) = lispAtom("retrieve");
  1031.     root_result_relation(root) = LispNil;
  1032.  
  1033.     /*
  1034.      * Now go to the target list (which must have exactly 1 Resdom
  1035.      * node, and change the 'resno' to 1
  1036.      */
  1037.     targetList = parse_targetlist(parseTree);
  1038.     set_resno((Resdom)tl_resdom(CAR(targetList)), (AttributeNumber)1);
  1039. }
  1040.  
  1041. /*-----------------------------------------------------------------
  1042.  *
  1043.  * prs2AttributeIsOfBasicType
  1044.  *
  1045.  * check if the given attribute is of a "basic" type.
  1046.  *-----------------------------------------------------------------
  1047.  */
  1048. bool
  1049. prs2AttributeIsOfBasicType(relOid, attrNo)
  1050. ObjectId relOid;
  1051. AttributeNumber attrNo;
  1052. {
  1053.     ObjectId typeId;
  1054.     char typtype;
  1055.  
  1056.     typeId = get_atttype(relOid, attrNo);
  1057.     typtype = get_typtype(typeId);
  1058.     if (typtype == '\0') {
  1059.     elog(WARN, "Cache lookup for type %ld failed...", typeId);
  1060.     }
  1061.  
  1062.     if (typtype == 'b') {
  1063.     return(true);
  1064.     } else {
  1065.     return(false);
  1066.     }
  1067. }
  1068.  
  1069. /*=============================== DEBUGGINF STUFF ================*/
  1070. LispValue
  1071. prs2ReadRule(fname)
  1072. char *fname;
  1073. {
  1074.     FILE *fp;
  1075.     int c;
  1076.     int count, maxcount;
  1077.     char *s1, *s2;
  1078.     LispValue l;
  1079.     LispValue StringToPlan();
  1080.  
  1081.     printf("--- prsReadRule.\n");
  1082.     AllocateFile();
  1083.     if (fname==NULL) {
  1084.     fp = stdin;
  1085.     printf(" reading rule from stdin.\n");
  1086.     } else {
  1087.     AllocateFile();
  1088.     fp = fopen(fname, "r");
  1089.     if (fp==NULL){
  1090.         printf(" Can not open rule file %s\n", fname);
  1091.         elog(WARN,"prs2ReadRule.... exiting...\n");
  1092.     } else {
  1093.         printf("Reading rule from file %s\n", fname);
  1094.     }
  1095.     }
  1096.  
  1097.     maxcount = 100;
  1098.     s1 = palloc(maxcount);
  1099.     if (s1 == NULL) {
  1100.     elog(WARN,"prs2ReadRule : out of memory!");
  1101.     }
  1102.  
  1103.     count = 0;
  1104.     while((c=getc(fp)) != EOF) {
  1105.     if (count >= maxcount) {
  1106.         maxcount = maxcount + 1000;
  1107.         s2 = palloc(maxcount);
  1108.         if (s2 == NULL) {
  1109.         elog(WARN,"prs2ReadRule : out of memory!");
  1110.         }
  1111.         bcopy(s1, s2, count);
  1112.         pfree(s1);
  1113.         s1 = s2;
  1114.     }
  1115.     s1[count] = c;
  1116.     count++;
  1117.     }
  1118.     s1[count+1] = '\0';
  1119.  
  1120.     l = StringToPlan(s1);
  1121.  
  1122.     printf("  list = \n");
  1123.     lispDisplay(l);
  1124.  
  1125.     if (fp!=stdin) {
  1126.     fclose(fp);
  1127.     FreeFile();
  1128.     }
  1129.  
  1130.     return(l);
  1131. }
  1132.